import config from '@/config'
import { getPublicImageAssetsFile } from '../tools'
import { layerMap } from './layer-id'

// 移除图层
export const removeLayer = (layerId: string) => {
    if (window.glMap.getLayer(layerId)) {
        window.glMap.removeLayer(layerId)
    }
}

// 移除数据
export const removeSource = (source: string) => {
    if (window.glMap.getSource(source)) {
        window.glMap.removeSource(source)
    }
}

// 同时移除图层和数据，仅仅使用在source名称和layer名称相同的情况
export const removeLayerAndSource = (layerId: string) => {
    const layer = window.glMap.getLayer(layerId)
    if (layer) {
        // 移除点击事件
        if (layer._click_handler) {
            window.glMap.off('click', layerId, layer._click_handler)
        }
        // 移除鼠标提示
        removePointLayerHoverTip(layerId)
        removeLayer(layerId)
        removeSource(layerId)
    }
}

// 显示图层
export const showLayer = (layerId: string) => {
    if (window.glMap && window.glMap.getLayer(layerId)) {
        window.glMap.setLayoutProperty(layerId, 'visibility', 'visible')
    }
}

// 隐藏图层
export const hideLayer = (layerId: string) => {
    if (window.glMap && window.glMap.getLayer(layerId)) {
        window.glMap.setLayoutProperty(layerId, 'visibility', 'none')
    }
}

// 是否存在图层
export const hasLayer = (layerId: string) => {
    if (window.glMap && window.glMap.getLayer(layerId)) {
        return true
    }
    return false
}

// 打开地图弹窗
export const showMapPop = (params: {
    VueComponent: any // vue组件
    properties: Record<string, any> // vue组件的props属性
    coordinates: number[] // 坐标
    offset?: [number, number]
}) => {
    // 清理老的
    if (window.popContent) {
        window.popContent.unmount()
        window.popContent = null
    }
    // 打开弹窗
    if (window.glPop) {
        window.glPop.remove()
        window.glPop = null
    }
    // 实例化vue组件
    window.popContent = createApp(params.VueComponent, {
        properties: params.properties,
    })
    // 生成dom
    const parent = document.createElement('div')
    const $el = window.popContent.mount(parent).$el
    // 偏移位置
    const offset = params.offset || [0, -12]
    window.glMap.easeTo({
        center: [params.coordinates[0], params.coordinates[1]],
        speed: 0.2,
        curve: 1.0,
        offset: [0, 150],
    })
    // 构建弹窗
    window.glPop = new window.mapboxgl.Popup({
        closeOnClick: true,
        closeButton: false,
        offset,
        className: 'map-pop-style',
    })
        .setLngLat(params.coordinates)
        .setDOMContent($el)
        .setMaxWidth('none')
        .addTo(window.glMap)
    window.glPop.once('close', () => {
        removeMapPop()
    })
}

// 移除地图弹窗
export const removeMapPop = () => {
    if (window.popContent) {
        window.popContent.unmount()
        window.popContent = null
    }
    if (window.glPop) {
        window.glPop.remove()
        window.glPop = null
    }
}

// 添加点位滑动提示
export const addPointLayerHoverTip = (layerId: string, nameField = 'name') => {
    if (window.glMap && window.glMap.getLayer(layerId) && nameField) {
        const layer = window.glMap.getLayer(layerId)
        layer._tip_mouseenter_handler = (e: any) => {
            window.glMap.getCanvas().style.cursor = 'pointer'
            const coordinates = e.features[0].geometry.coordinates.slice()
            const description = e.features[0].properties[nameField]

            while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
                coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360
            }
            if (window.glTip) {
                window.glTip.remove()
            }
            window.glTip = new window.mapboxgl.Popup({
                className: 'map-tooltip-style',
                closeOnClick: false,
                closeButton: false,
            })
                .setLngLat(coordinates)
                .setHTML(description)
                .addTo(window.glMap)
            window.glMap.triggerRepaint()
        }
        window.glMap.on('mouseenter', layerId, layer._tip_mouseenter_handler)
        layer._tip_mouseleave_handler = () => {
            window.glMap.getCanvas().style.cursor = ''
            window.glTip.remove()
        }
        window.glMap.on('mouseleave', layerId, layer._tip_mouseleave_handler)
    }
}

// 移除滑动点位提示
export const removePointLayerHoverTip = (layerId: string) => {
    if (window.glMap && window.glMap.getLayer(layerId)) {
        const layer = window.glMap.getLayer(layerId)
        if (layer._tip_mouseenter_handler) {
            window.glMap.off('mouseenter', layerId, layer._tip_mouseenter_handler)
        }
        if (layer._tip_mouseleave_handler) {
            window.glMap.off('mouseleave', layerId, layer._tip_mouseleave_handler)
        }
    }
}

// 添加普通点位
export const addCommonPointLayer = (options: {
    layerId: string
    layerOptions: any
    beforeLayerId?: string
    geojson: any
    onClick?: (e: any) => void
    hoverTipField?: string
}) => {
    // 添加数据资源
    window.glMap.addSource(options.layerId, {
        type: 'geojson',
        data: options.geojson,
    })
    // 添加图层资源
    const layer = window.glMap.addLayer(
        {
            id: options.layerId,
            source: options.layerId,
            ...options.layerOptions,
        },
        options.beforeLayerId,
    )
    // 添加图层点位点击事件
    if (layer._click_handler) {
        window.glMap.off('click', options.layerId, layer._click_handler)
    }
    layer._click_handler = (e: any) => {
        options.onClick && options.onClick(e)
    }
    window.glMap.on('click', options.layerId, layer._click_handler)
    // 添加鼠标提示
    removePointLayerHoverTip(options.layerId)
    addPointLayerHoverTip(options.layerId, options.hoverTipField ?? 'name')
}

// 组合型移除
export const removeCombinedLayers = (layerIds: string[]) => {
    layerIds.forEach(item => {
        const layer = window.glMap.getLayer(item)
        if (layer) {
            // 移除图层
            removeLayerAndSource(item)
        }
    })
}

// 添加图片到地图上
export const addImageToMap = async (imgList: { imageName: string; imagePath: string }[]) => {
    const promises: any[] = []
    imgList.forEach(item => {
        if (window.glMap.hasImage(item.imageName)) {
            return
        }
        const promise = new Promise(resolve => {
            window.glMap.loadImage(
                getPublicImageAssetsFile(item.imagePath),
                (error: any, image: any) => {
                    if (error) {
                        console.error(error)
                        resolve(true)
                        return
                    }
                    window.glMap.addImage(item.imageName, image)
                    resolve(true)
                },
            )
        })
        promises.push(promise)
    })
    await Promise.all(promises)
    return true
}

// 自动移除图层 移除layerMap中定义的图层
export const autoRemoveCommonLayer = () => {
    Object.keys(layerMap).forEach(item => {
        removeLayerAndSource(layerMap[item as keyof typeof layerMap])
    })
}

// 获取杭州范围
export const getHangzhouGeojson = async () => {
    const hzGeojson = await fetch(`${config.publicPath}json/hz-city.json`).then(res => res.json())
    localStorage.setItem('hangzhou-area-geojson', JSON.stringify(hzGeojson))
}

// 点位是否在杭州范围 [lng, lat]
// 杭州范围在App.vue中提前获取
export const pointIsInHangzhou = (point: any) => {
    // 判断参数是否合法
    const lng = point[0]
    const lat = point[1]
    if (!lng && !lat) return false

    let hzGeojson = null
    const hzGeojsonStr = localStorage.getItem('hangzhou-area-geojson')
    if (hzGeojsonStr) {
        hzGeojson = JSON.parse(hzGeojsonStr)
    }

    if (hzGeojson) {
        const pt = window.turf.point(point)
        const polygonPoints = hzGeojson.features[0].geometry.coordinates[0]
        const poly = window.turf.polygon([polygonPoints])
        return window.turf.booleanPointInPolygon(pt, poly) as boolean
    }

    return false
}

// 移除markers
export const removeMarkers = (markers: any[]) => {
    if (!markers) return
    if (Object.prototype.toString.call(markers) === '[object Array]') {
        markers.forEach(mk => {
            if (mk) {
                mk.remove()
                mk = null
            }
        })
    }
    if (Object.prototype.toString.call(markers) === '[object]') {
        markers.forEach(key => {
            let mk = markers[key]
            if (mk) {
                mk.remove()
                mk = null
            }
        })
    }
}
